const h = (tag, props, children) => {
  // h函数就是返回一个对象
  return {
    tag,
    props,
    children
  }
}

const mount = (vnode, container)=>{
  // 1、vnode转化为真实dom，并在vnode保留一份
  const el = vnode.el = document.createElement(vnode.tag)
  // 2、处理props
  if (vnode.props) {
    for (let key in vnode.props) {
      const value=vnode.props[key]
      // 2.1处理事件，是不是on开头的
      if (key.startsWith('on')) {
        el.addEventListener(key.slice(2).toLowerCase(),value)
      } else {
        el.setAttribute(key,value)
      }
    }
  }
  // 3、处理children,这里只考虑两种：string|Arrary
  if (vnode.children) {
    // 3.1如果是字符串，就仅仅是文本
    if (typeof vnode.children === 'string') {
      el.textContent=vnode.children
    }
    else {
      vnode.children.forEach(element => {
        // 3.2递归遍历
        mount(element,el)
      });
    }
  }
  console.log(el);
  
  // 4、将el挂载到container中
  container.appendChild(el)
}

const patch = (n1, n2) => {
  // 1、节点类型都不同直接卸载更新
  if (n1.tag !== n2.tag) {
    // n1.el在mount保存一份了
    const n1Parent = n1.el.parentElement;
    n1Parent.removeChild(n1.el);
    mount(n2, n1Parent);
  }
  else {
    // 2、取出element，并在n2中进行保存,引用类型，都会修改，和mount统一规范
    const el = n2.el = n1.el;
    // 3、处理props：Object
    const oldProps = n1.props || {};
    const newProps = n2.props || {};
    for (const key in newProps) {
      const oldValue = oldProps[key];
      const newValue = newProps[key];
      // 3.1新增props
      if (newValue !== oldValue) {
        // 挂载value方法
        if (key.startsWith('on')) {
          el.addEventListener(key.slice(2).toLowerCase(),newValue)
        }
        else {
          el.setAttribute(key,newValue)
        }
      }
    }
    // 3.2删除旧的props
    for (const key in oldProps) {
        if (key.startsWith('on')) {
          el.removeEventListener(key.slice(2).toLowerCase(),oldProps[key])
        }
        if(!(key in newProps)) {
          el.removeAttribute(key)
        }
    }

    // 4、处理children：string|Array
    const oldChildren = n1.children || [];
    const newChildren = n2.children || [];
    // 如果是字符串直接替换,当然还再可以做一些edge case
    if (typeof newChildren === 'string') {
      el.innerHTML = newChildren
    }
    else {
      // 旧节点是字符串，新节点是数组
      if (typeof oldChildren === 'string') {
        newChildren.forEach(item => {
          // 挂载子元素
          mount(item,el)
        })
      } else {
        const commonLength = Math.min(oldChildren.length, newChildren.length)
        // 两个都是数组，对短数组循环递归，进行比较更新
        for (let i = 0; i < commonLength; i++){
          patch(oldChildren[i],newChildren[i])
        }
        if (newChildren.length > oldChildren.length) {
          newChildren.slice(commonLength).forEach(item => {
            mount(item,el)
          })
        }
        if (newChildren.length < oldChildren.length) {
          oldChildren.slice(commonLength).forEach(item => {
            el.removeChild(item.el)
          })
        }
      }
    }

  }
}